{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 激活函数ReLU"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#encoding=utf8\n",
    "import numpy as np\n",
    "def relu(x):\n",
    "    '''\n",
    "    x:负无穷到正无穷的实数\n",
    "    '''\n",
    "    #********* Begin *********#\n",
    "    # x = np.asarray(x)\n",
    "    # return np.where(x<0, 0, x)\n",
    "    if x < 0:\n",
    "        return 0\n",
    "    else:\n",
    "        return x\n",
    "    #********* End *********#\n",
    "\n",
    "# relu([1,2,-1])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 第3关：反向传播算法"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#encoding=utf8\n",
    "import os\n",
    "\n",
    "if os.path.exists('./step2/result.csv'):\n",
    "    os.remove('./step2/result.csv')\n",
    "    \n",
    "#********* Begin *********#\n",
    "#获取训练数据\n",
    "train_data = pd.read_csv('./step2/train_data.csv')\n",
    "#获取训练标签\n",
    "train_label = pd.read_csv('./step2/train_label.csv')\n",
    "train_label = train_label['target']\n",
    "#获取测试数据\n",
    "test_data = pd.read_csv('./step2/test_data.csv')\n",
    "\n",
    "from sklearn.neural_network import MLPClassifier\n",
    "# print(train_data.shape)\n",
    "mlp = MLPClassifier(solver='lbfgs',max_iter =500,\n",
    "           alpha=1, hidden_layer_sizes=(8,4, 2))\n",
    "mlp.fit(train_data, train_label)\n",
    "\n",
    "import pandas as pd\n",
    "result = mlp.predict(test_data)\n",
    "res = pd.DataFrame(result, columns=['result'])\n",
    "res.to_csv('./step2/result.csv')\n",
    "#********* End *********#"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 第四关：使用pytorch搭建神经网络识别手写字"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#encoding=utf8\n",
    "import torch\n",
    "import torch.nn as nn\n",
    "from torch.autograd import Variable\n",
    "import torch.utils\n",
    "import torch.utils.data as Data\n",
    "import torch.utils.data\n",
    "import torchvision\n",
    "import os\n",
    "if os.path.exists('./step3/cnn.pkl'):\n",
    "    os.remove('./step3/cnn.pkl')\n",
    "    \n",
    "#加载数据             \n",
    "train_data = torchvision.datasets.MNIST(\n",
    "    root='./step3/mnist/',\n",
    "    train=True,                                     # this is training data\n",
    "    transform=torchvision.transforms.ToTensor(),    # Converts a PIL.Image or numpy.ndarray to                                                    \n",
    "    download=False,\n",
    ")\n",
    "#取6000个样本为训练集\n",
    "# train_data_tiny = []\n",
    "\n",
    "# for i in range(6000):\n",
    "#     train_data_tiny.append(train_data[i])\n",
    "\n",
    "# train_data = train_data_tiny\n",
    "\n",
    "train_data = torch.utils.data.DataLoader(train_data, batch_size=64, shuffle=True)\n",
    "\n",
    "#********* Begin *********#\n",
    "#构建卷积神经网络模型\n",
    "class CNN(nn.Module):\n",
    "    def __init__(self):\n",
    "        super(CNN, self).__init__()\n",
    "        self.conv1 = nn.Sequential(         # input shape (1, 28, 28)\n",
    "            nn.Conv2d(\n",
    "                in_channels=1,              # input height\n",
    "                out_channels=16,            # n_filters\n",
    "                kernel_size=5,              # filter size\n",
    "                stride=1,                   # filter movement/step\n",
    "                padding=2,                  # if want same width and length of this image after con2d, padding=(kernel_size-1)/2 if stride=1\n",
    "            ),                              # output shape (16, 28, 28)\n",
    "            nn.ReLU(),                      # activation\n",
    "            nn.MaxPool2d(kernel_size=2),    # choose max value in 2x2 area, output shape (16, 14, 14)\n",
    "        )\n",
    "        self.conv2 = nn.Sequential(         # input shape (16, 14, 14)\n",
    "            nn.Conv2d(16, 32, 5, 1, 2),     # output shape (32, 14, 14)\n",
    "            nn.ReLU(),                      # activation\n",
    "            nn.MaxPool2d(2),                # output shape (32, 7, 7)\n",
    "        )\n",
    "        self.out = nn.Linear(32 * 7 * 7, 10)   # fully connected layer, output 10 classes\n",
    "    def forward(self, x):\n",
    "        x = self.conv1(x)\n",
    "        x = self.conv2(x)\n",
    "        x = x.view(x.size(0), -1)           # flatten the output of conv2 to (batch_size, 32 * 7 * 7)\n",
    "        output = self.out(x)\n",
    "        return output\n",
    "cnn = CNN()\n",
    "\n",
    "#SGD表示使用随机梯度下降方法，lr为学习率，momentum为动量项系数\n",
    "optimizer = torch.optim.SGD(cnn.parameters(), lr = 0.01, momentum=0.9)\n",
    "#交叉熵损失函数\n",
    "loss_func = nn.CrossEntropyLoss()\n",
    "\n",
    " \n",
    "'''定义训练函数'''\n",
    "def train(dataloader,model,loss_fn,optimizer, epoch_num = 20):\n",
    "    for epoch in range(1, epoch_num+1):\n",
    "        model.train()\n",
    "        # 记录优化次数\n",
    "        # num=1\n",
    "        for X,y in dataloader:\n",
    "            # 因为网站测评的torch版本较低，这里需要对X和y进行类型转换\n",
    "            X = Variable(X) \n",
    "            y = Variable(y)\n",
    "            # 自动初始化权值w\n",
    "            pred=model.forward(X)\n",
    "            loss=loss_fn(pred,y) # 计算损失值\n",
    "            optimizer.zero_grad()\n",
    "            loss.backward()\n",
    "            optimizer.step()\n",
    "            # loss_value=loss.item()\n",
    "            # print(f'loss:{loss_value},[numbes]:{num}')\n",
    "            # num+=1\n",
    "\n",
    "train(train_data, cnn, loss_func, optimizer, 5)\n",
    "\n",
    "#********* End *********#\n",
    "#保存模型\n",
    "torch.save(cnn.state_dict(), './step3/cnn.pkl')\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "下面是标答，我说我寻思怎么运行时间超时呢，原来我删掉了取6000个样本的代码，导致我DataLoader直接用的是60000个样本，所以时间超时了。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#encoding=utf8\n",
    "import torch\n",
    "import torch.nn as nn\n",
    "from torch.autograd import Variable\n",
    "import torch.utils.data as Data\n",
    "import torchvision\n",
    "import os\n",
    "if os.path.exists('./step3/cnn.pkl'):\n",
    "    os.remove('./step3/cnn.pkl')\n",
    "    \n",
    "#加载数据             \n",
    "train_data = torchvision.datasets.MNIST(\n",
    "    root='./step3/mnist/',\n",
    "    train=True,                                     # this is training data\n",
    "    transform=torchvision.transforms.ToTensor(),    # Converts a PIL.Image or numpy.ndarray to                                                    \n",
    "    download=False,\n",
    ")\n",
    "#取6000个样本为训练集\n",
    "train_data_tiny = []\n",
    "for i in range(6000):\n",
    "    train_data_tiny.append(train_data[i])\n",
    "train_data = train_data_tiny\n",
    "#********* Begin *********#\n",
    "#mini_batch\n",
    "train_loader = Data.DataLoader(dataset=train_data, batch_size=64, shuffle=True)\n",
    "#构建卷积神经网络模型\n",
    "class CNN(nn.Module):\n",
    "    def __init__(self):\n",
    "        super(CNN, self).__init__()\n",
    "        self.conv1 = nn.Sequential(         # input shape (1, 28, 28)\n",
    "            nn.Conv2d(\n",
    "                in_channels=1,              # input height\n",
    "                out_channels=16,            # n_filters\n",
    "                kernel_size=5,              # filter size\n",
    "                stride=1,                   # filter movement/step\n",
    "                padding=2,                  # if want same width and length of this image after con2d, padding=(kernel_size-1)/2 if stride=1\n",
    "            ),                              # output shape (16, 28, 28)\n",
    "            nn.ReLU(),                      # activation\n",
    "            nn.MaxPool2d(kernel_size=2),    # choose max value in 2x2 area, output shape (16, 14, 14)\n",
    "        )\n",
    "        self.conv2 = nn.Sequential(         # input shape (16, 14, 14)\n",
    "            nn.Conv2d(16, 32, 5, 1, 2),     # output shape (32, 14, 14)\n",
    "            nn.ReLU(),                      # activation\n",
    "            nn.MaxPool2d(2),                # output shape (32, 7, 7)\n",
    "        )\n",
    "        self.out = nn.Linear(32 * 7 * 7, 10)   # fully connected layer, output 10 classes\n",
    " \n",
    "    def forward(self, x):\n",
    "        x = self.conv1(x)\n",
    "        x = self.conv2(x)\n",
    "        x = x.view(x.size(0), -1)           # flatten the output of conv2 to (batch_size, 32 * 7 * 7)\n",
    "        output = self.out(x)\n",
    "        return output    \n",
    "  \n",
    "cnn = CNN()\n",
    "#构建优化器与损失函数\n",
    "optimizer = torch.optim.Adam(cnn.parameters(), lr=0.001)   \n",
    "loss_func = nn.CrossEntropyLoss()                       \n",
    " \n",
    "#训练模型\n",
    "for step, (x, y) in enumerate(train_loader):   \n",
    "    b_x = Variable(x)   \n",
    "    b_y = Variable(y)   \n",
    " \n",
    "    output = cnn(b_x)               \n",
    "    loss = loss_func(output, b_y)   \n",
    "    optimizer.zero_grad()           \n",
    "    loss.backward()                 \n",
    "    optimizer.step()                \n",
    "           \n",
    "#********* End *********#\n",
    "#保存模型\n",
    "torch.save(cnn.state_dict(), './step3/cnn.pkl')"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "tf38",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.19"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
